/*
 * comandos.c
 *
 *  Created on: 11/12/2009
 *      Author: teledhil
 */

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/unistd.h>
#include <sys/socket.h>
#include <netdb.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "comandos.h"
#include "comunicacion.h"
#include "consola.h"
#include "downloads.h"
#include "uploads.h"
#include "escuchas.h"
#include "variablesGlobales.h"
#include "test_funcionHilo.h"

int help() {

	output_debug("help");
	output_program("A typical user session goes like this:");
	output_program("");
	output_program("    /connect localhost:7101");
	output_program("    /auth alcortes");
	output_program("    /list");
	output_program("    /join #ro2");
	output_program("    hello");
	output_program("    /leave");
	output_program("    /disconnect");
	output_program("    /quit");
	output_program("");
	output_program("The full list of available commands are:");
	output_program("");
	output_program("    /help                    Show this text.");
	output_program("    /connect <host>:<port>   Connect to a server.");
	output_program("    /auth <nick>             Authenticate with the server,");
	output_program(
			"                             sets nick, username & real name.");
	output_program(
			"    /list                    Lists all current irc channels,");
	output_program("                             number of users, and topic.");
	output_program(
			"    /join [<channel>]        Join a channel or tell which is");
	output_program("                             the current channel.");
	output_program("    /leave                   Leaves your current channel.");
	output_program(
			"    /who                     List users in current channel.");
	output_program("    /msg <txt>               Send <txt> to the channel.");
	output_program(
			"    /offer <file> <nick>     Launch a DCC server for a file");
	output_program(
			"                             transfer.  The recipient must accept");
	output_program(
			"                             your offer with a '/download'.");
	output_program("    /download <host:port> <file>");
	output_program(
			"                             Starts a file transfer by DCC.");
	output_program(
			"                             The  sender must first have offered");
	output_program(
			"                             the file with an '/offer' command.");
	output_program("    /disconnect              Disconnect from server.");
	output_program("    /quit                    Close program.");
	output_program("    /nop [<text>]            (debugging) no operation,");
	output_program("                             just echoes <text> back.");
	output_program("    /sleep [<secs>]          (debugging) pause for <secs>");
	output_program("                             seconds.");
	output_program("");
	output_program(
			"Lines from the user that don't begin with '/' are equivalent to");
	output_program("");
	output_program("    /msg line");
	output_program("");
	output_program(
			"Lines beginning with \"*** \" are messages from the program.");
	output_program("Lines beginning with \"<user> \" are messages from <user>.");
	output_program(
			"Lines beginning with \"DDD \" are debug messages from the program.");
	output_program(
			"Lines beginning with \"> \" are your messages to other users.");
	output_program("The rest of the lines are echoes of the user commands.\n\n");

	return 0;
}

int connect(char *host, int port) {

	output_debug("connect: host=|%s|, port=|%d|", host, port);

	if (state_connected) {
		/*if ((strcmp(host, servidor) == 0) && (puerto == port)) {
		 output_program("Already connected to %s:%d", host, port);
		 return -1;
		 } else {
		 disconnect();
		 }*/
		output_program("Already connected to %s:%d", servidor, puerto);
		return -1;
	}

	/*Obtiene socket*/
	if ((socketServer = crear_conexion()) < 0) {
		return -1;
	}

	/*Conecta con servidor*/
	if (conectar(socketServer, host, port) < 0) {
		output_program("Unable to connect to server %s:%d", host, port);
		return -1;
	}

	state_connected = true;
	strcpy(servidor, host);
	puerto = port;

	output_program("Connected to server %s:%d", host, port);

	/*Lanza thread de escucha*/
	if (hiloEscuchas.start(funcion_escuchas) < 0) {
		output_program(
				"Unable to listen to server. Currently listening to another server");
		return -1;
	}

	/*Saluda al servidor*/

	return 0;
}

int auth(char *nick) {
	/*Envia mensajes NICK + USER*/
	char mensaje[100];

	output_debug("auth: nick=|%s|", nick);

	if (!state_connected) {
		//output_error("%s", ERROR_NOT_CONNECTED_TO_SERVER);
		output_program("Unable to authenticate, not connected to any server");
		return -1;
	}

	//Mensaje NICK
	sprintf(mensaje, "%s%c%s%c%c", IRC_NICK, SPACE, nick, CR, LF);
	enviar_mensaje(socketServer, mensaje, strlen(mensaje));
	memset(mensaje, '\0', 100);

	//Mensaje USER
	sprintf(mensaje, "%s%c%s%c0%c*%c%c%s%c%c", IRC_USER, SPACE, nick,
			SPACE/*, MODE*/, SPACE/*, UNUSED*/, SPACE, COLON, nick, CR, LF);
	enviar_mensaje(socketServer, mensaje, strlen(mensaje));

	return 0;
}

int list() {
	/*Envia mensaje LIST*/
	char mensaje[100];

	output_debug("list");

	if (!state_connected) {
		//output_error("%s", ERROR_NOT_CONNECTED_TO_SERVER);
		output_program("Unable to list channels: not connected to server");
		return -1;
	}

	sprintf(mensaje, "%s%c%c", IRC_LIST, CR, LF);
	enviar_mensaje(socketServer, mensaje, strlen(mensaje));

	return 0;
}

int join(char *channel) {
	/*Envia mensajes LIST*/
	char mensaje[100];

	output_debug("join: channel=|%s|", channel);

	if (!state_connected) {
		//output_error("%s", ERROR_NOT_CONNECTED_TO_SERVER);
		output_program("Unable to join channel: not connected to server");
		return -1;
	}

	//Abandona canal actual (si esta en alguno)
	sprintf(mensaje, "%s%c0%c%c", IRC_JOIN, SPACE, CR, LF);
	enviar_mensaje(socketServer, mensaje, strlen(mensaje));
	memset(mensaje, '\0', 100);

	//Entra en el nuevo canal
	sprintf(mensaje, "%s%c%s%c%c", IRC_JOIN, SPACE, channel, CR, LF);
	enviar_mensaje(socketServer, mensaje, strlen(mensaje));

	return 0;
}

int leave() {
	/*Envia mensaje JOIN*/
	char mensaje[100];

	output_debug("leave");

	if (!state_connected) {
		output_error("%s", ERROR_NOT_CONNECTED_TO_SERVER);
		return -1;
	}

	//Abandona canal actual (si esta en alguno)
	if (part(channel) < 0) {
		//Si falla lo anterior, se abandonan todos los canales
		sprintf(mensaje, "%s%c0%c%c", IRC_JOIN, SPACE, CR, LF);
		enviar_mensaje(socketServer, mensaje, strlen(mensaje));
	}

	return 0;
}

int part(char *channel) {
	/*Envia mensaje JOIN*/
	char mensaje[100];

	output_debug("part");

	if (!state_connected) {
		output_error("%s", ERROR_NOT_CONNECTED_TO_SERVER);
		return -1;
	}

	//Abandona el canal indicado
	sprintf(mensaje, "%s%c%s%c%c", IRC_PART, SPACE, channel, CR, LF);
	enviar_mensaje(socketServer, mensaje, strlen(mensaje));

	return 0;
}

int ping(char *server1, char *server2) {
	/*Envia mensaje JOIN*/
	char mensaje[100];

	output_debug("ping");

	if (!state_connected) {
		output_error("%s", ERROR_NOT_CONNECTED_TO_SERVER);
		return -1;
	}
	if (server1 == NULL) {
		sprintf(mensaje, "%s%c%c", IRC_PING, CR, LF);
		enviar_mensaje(socketServer, mensaje, strlen(mensaje));
	} else if (server2 == NULL) {
		//Hace ping al servidor indicado
		sprintf(mensaje, "%s%c%s%c%c", IRC_PING, SPACE, server1, CR, LF);
		enviar_mensaje(socketServer, mensaje, strlen(mensaje));
	} else {
		//Hace ping al servidor indicado
		sprintf(mensaje, "%s%c%s%c%s%c%c", IRC_PING, SPACE, server1, SPACE,
				server2, CR, LF);
		enviar_mensaje(socketServer, mensaje, strlen(mensaje));
	}

	return 0;
}

int pong(char *server1, char *server2) {
	/*Envia mensaje JOIN*/
	char mensaje[100];

	output_debug("pong");

	if (!state_connected) {
		output_error("%s", ERROR_NOT_CONNECTED_TO_SERVER);
		return -1;
	}
	if (server1 == NULL) {
		sprintf(mensaje, "%s%c%c", IRC_PONG, CR, LF);
		enviar_mensaje(socketServer, mensaje, strlen(mensaje));
	} else if (server2 == NULL) {
		//Hace pong al servidor indicado
		sprintf(mensaje, "%s%c%s%c%c", IRC_PONG, SPACE, server1, CR, LF);
		enviar_mensaje(socketServer, mensaje, strlen(mensaje));
	} else {
		//Hace pong al servidor indicado
		sprintf(mensaje, "%s%c%s%c%s%c%c", IRC_PONG, SPACE, server1, SPACE,
				server2, CR, LF);
		enviar_mensaje(socketServer, mensaje, strlen(mensaje));
	}

	return 0;
}

int who() {
	/*Envia mensaje WHO*/
	char mensaje[100];

	output_debug("who");

	if (!state_connected) {
		output_error("%s", ERROR_NOT_CONNECTED_TO_SERVER);
		return -1;
	}

	if (strcmp("", channel) == 0) { //Comprueba que este en un canal
		output_program("You are not in any channel");
	}

	//Envia mensaje who
	sprintf(mensaje, "%s%c*%c%c", IRC_WHO, SPACE, CR, LF);
	enviar_mensaje(socketServer, mensaje, strlen(mensaje));

	return 0;
}

int msg_all(char *text) {
	char mensaje[512];

	output_debug("msg: text=|%s|", text);

	if (!state_connected) {
		output_error("%s", ERROR_NOT_CONNECTED_TO_SERVER);
		return -1;
	}

	if (strcmp(channel, "") == 0) {
		output_program("You must join a channel first");
		return -1;
	}

	sprintf(mensaje, "%s%c%s%c%c%s%c%c", IRC_PRIVMSG, SPACE, channel, SPACE,
			COLON, text, CR, LF);
	if (enviar_mensaje(socketServer, mensaje, strlen(mensaje)) < 0) {
		return -1;
	} else {
		output_me("%s", text);
	}

	return 0;
}

int msg_private(char *user, char *text) {
	char mensaje[512];

	output_debug("msg: text=|%s|", text);

	if (!state_connected) {
		output_error("%s", ERROR_NOT_CONNECTED_TO_SERVER);
		return -1;
	}

	sprintf(mensaje, "%s%c%s%c%c%s%c%c", IRC_PRIVMSG, SPACE, user, SPACE,
			COLON, text, CR, LF);
	if (enviar_mensaje(socketServer, mensaje, strlen(mensaje)) < 0) {
		return -1;
	} else {
		output_me("%s", text);
	}

	return 0;
}

int disconnect() {
	char mensaje[100];

	output_debug("disconnect");

	/*Se despide del servidor*/

	if (state_connected) {
		//Abandona canal actual (si esta en alguno)
		sprintf(mensaje, "%s%c%c%s%c%c", IRC_QUIT, SPACE, COLON,
				IRC_DISCONNECTING, CR, LF);
		enviar_mensaje(socketServer, mensaje, strlen(mensaje));
		output_program("Disconnected from server");

		state_connected = false;
	} else {
		output_program("Already disconnected from server");
	}

	/*Cierra thread de escucha*/
	hiloEscuchas.stop();

	/*Cierra hilo descargas*/
	hiloDownloads.stop();

	/*Cierra hilo subidas*/
	hiloUploads.stop();

	/*Desconecta del servidor*/
	cerrar_conexion(socketServer);

	/*Cierra socket*/
	socketServer = 0;

	return 0;
}

int quit() {

	output_debug("quit");

	/*Avisa que el programa debe finalizar*/
	state_powerOff = true;

	if (state_connected) {
		disconnect();
	}
	//hiloDownloads.stop();

	output_program("bye!");

	return 0;
}

int nop(char *text) {

	output_debug("nop: text=|%s|", text);

	return 0;
}

int sleep_ircc(int secs) {

	output_debug("sleep: secs=|%d|", secs);

	state_sleep = secs;
	sleep(secs);
	state_sleep = 0;

	return 0;
}

int offer(char *filename, char *nick) {

	output_debug("offer: filename=|%s|, nick=|%s|", filename, nick);

	if (!state_connected) {
		output_error("%s", ERROR_NOT_CONNECTED_TO_SERVER);
		return -1;
	}
	if (file_ul_fd > 0) {
		output_program("Unable to offer file. Another file has been offered");
		output_debug("file_ul_fd=%d", file_ul_fd);
		return -1;
	}

	strcpy(file_ul_path, filename);
	strcpy(file_ul_nick, nick);

	/*Cierra hilo subidas*/
	hiloUploads.stop();
	/*Lanza thread de transferencia*/
	if (hiloUploads.start(funcion_uploads) < 0) {
		output_program("Unable to offer file. Another file has been offered");
		return -1;
	}

	return 0;
}

int download(char *filename, char *host, int port) {

	output_debug("download: filename=|%s|, host=|%s|, port=|%d|", filename,
			host, port);

	if (file_dl_fd > 0) {
		output_program(
				"Unable to download file. Another download is taking place");
		output_debug("file_dl_fd=%d", file_dl_fd);
		return -1;
	}

	strcpy(file_dl_path, filename);

	/*Obtiene socket*/
	if ((socketDownload = crear_conexion()) < 0) {
		return -1;
	}

	/*Conecta con servidor*/
	if (conectar(socketDownload, host, port) < 0) {
		output_program("Unable to connect to server %s:%d", host, port);
		return -1;
	}

	state_connected = true;

	/*Lanza thread de escucha*/
	if (hiloDownloads.start(funcion_downloads) < 0) {
		output_program(
				"Unable to download file. Another download is taking place");
		return -1;
	}

	return 0;
}

